#include "stub.h"
#include "genericv.h"
#include "genericdao.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define STATIC_B_SZ 4096

char *myStrCat(char *dst, char *src, long *dstBufSz)
{
  int sz = (dst==0)?0:strlen(dst);
  char *new = 0;

  sz += strlen(src);
  if(sz>=*dstBufSz)
  {
    new = (char *)realloc(dst,sizeof(char)*(sz+1024));
    if(new) *dstBufSz = sz+1024;
    else if(dst) free(dst);
  }

  return new;
}

GenericDAO *currentDAO = 0;

void setCurrentDAO(GenericDAO *dao)
{
  currentDAO = dao;
}

GenericDAO *getCurrentDAO()
{
  return currentDAO;
}

GenericDAO *createDAO(BDConnection *connection)
{
  GenericDAO *dao = (GenericDAO *)malloc(sizeof(GenericDAO));

  if(!dao) return 0;

  dao->conn = connection;

  return dao;
}

void deleteDAO(GenericDAO *dao)
{
  bdDisconnect(dao->conn);
  free(dao);
}

void *loadEntityById(GenericDAO *dao, char *tableName, void *iptr, char *id)
{
  int i,j=0;
  GenericI *gi = (GenericI *) iptr;
  char staticBuf[STATIC_B_SZ];
  char *query=staticBuf;

  FieldEntry *fields = gi->getFields();

  if(!fields) goto ERR;

  int sz = snprintf(query,STATIC_B_SZ,"select * from %s where id=%s limit 1",tableName,id);
  if(sz>=STATIC_B_SZ)
  {
    query = malloc(sizeof(char)*(sz+1));
    if(!query) goto ERR;
    sprintf(query,"select * from %s where id=%s limit 1",tableName,id);
  }

  BDResult *result = bdExecQuery(dao->conn,query,0,0);
  if(!result) goto ERR;

  if(!bdNextRow(result)) goto ERR;
  void *obj = gi->create();
  if(!obj) goto ERR;

  for(i=0; i<result->cols; i++)
  {
    char *colName = bdResultColName(result,i);
    if(!colName) continue;

    for(j=0; fields[j].fieldName; j++)
    {
      if(strcmp(colName,fields[j].fieldName)) continue;

      GenericVar *gvar = (GenericVar *)((long)obj + fields[j].fieldOffset);
      setVarSTR(gvar,bdResultVal(result,j));
    }
  }

  if(query!=staticBuf) free(query);
  return obj;
ERR:
  if(query && (query!=staticBuf)) free(query);
  if(result) bdFreeResult(result);
  return 0;
}

BDError saveEntity(GenericDAO *dao, char *tableName, void *iptr, void *obj)
{
  int i;
  GenericI *gi = (GenericI *) iptr;
  char *NULL_VAL = "NULL";
  char staticBuf[STATIC_B_SZ];
  char *query=staticBuf;
  char **values;
  int numVals = 0;

  if(!query) goto ERR;

  FieldEntry *fields = gi->getFields();
  if(!fields) goto ERR;

//calc length of query
  int querySz = strlen("insert into ");
  querySz += strlen(tableName);
  querySz += strlen("(");
  for(i=0; fields[i].fieldName; i++)
  {
    GenericVar *gvar = (GenericVar *)((long)obj+fields[i].fieldOffset);
    char *strval = getVarSTR(gvar);

    if(strval)
    {
      ++numVals;
      if(numVals>1) querySz+=strlen(",");
      querySz += strlen(fields[i].fieldName);
    }
  }
  querySz += strlen(") values (");

  numVals=0;
  for(i=0; fields[i].fieldName; i++)
  {
    char fieldTag[128];
    GenericVar *gvar = (GenericVar *)((long)obj+fields[i].fieldOffset);
    char *strval = getVarSTR(gvar);

    if(strval)
    {
      ++numVals;
      if(!strcmp(bdType(),"postgres")) sprintf(fieldTag,"$%d",numVals);
      else if(!strcmp(bdType(),"mysql")) sprintf(fieldTag,"?");

      if(numVals>1) querySz+=strlen(",");
      querySz += strlen(fieldTag);
    }
  }
  querySz += strlen(")");

//build query
  if(querySz>=STATIC_B_SZ)
  {
    query = malloc(sizeof(char)*(querySz+1));
    if(!query) goto ERR;
  }
  query[0] = 0;

  strcat(query,"insert into ");
  strcat(query,tableName);
  strcat(query,"(");
  numVals=0;
  for(i=0; fields[i].fieldName; i++)
  {
    GenericVar *gvar = (GenericVar *)((long)obj+fields[i].fieldOffset);
    char *strval = getVarSTR(gvar);

    if(strval)
    {
      ++numVals;
      if(numVals>1) strcat(query,",");
      strcat(query,fields[i].fieldName);
    }
  }
  strcat(query,") values (");

  numVals = 0;
  for(i=0; fields[i].fieldName; i++)
  {
    char fieldTag[128];
    GenericVar *gvar = (GenericVar *)((long)obj+fields[i].fieldOffset);
    char *strval = getVarSTR(gvar);

    if(strval)
    {
      ++numVals;
      if(!strcmp(bdType(),"postgres")) sprintf(fieldTag,"$%d",numVals);
      else if(!strcmp(bdType(),"mysql")) sprintf(fieldTag,"?");

      if(numVals>1) strcat(query,",");
      strcat(query,fieldTag);
    }
  }
  strcat(query,")");

  values = (char **)malloc(sizeof(char *)*numVals);
  if(!values) goto ERR;

  numVals=0;
  for(i=0; fields[i].fieldName; i++)
  {
    GenericVar *gvar = (GenericVar *)((long)obj+fields[i].fieldOffset);
    char *strval = getVarSTR(gvar);

    if(strval)
    {
      values[numVals]=strval;
      ++numVals;
    }
  }

  BDError result = bdExecCommand(dao->conn,query,values,numVals);

  if(query!=staticBuf) free(query);
  free(values);
  return result;
  
ERR:
  if(query && (query!=staticBuf)) free(query);
  if(values) free(values);
  return BD_E_ERROR;
}
